package com.zy.explore.common.interfaces.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 分页返回VO
 *
 * @author ChinaYin  主页:https://gitee.com/zy-explorej2ee 邮箱:zyexplorej2ee@sina.com
 * @date 2021年06月13日 15:14:11
 */
@ApiModel
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageVO<T> {

    /**
     * 页序数
     */
    @ApiModelProperty(value = "页序数", dataType = "int")
    private Integer pageNum;
    /**
     * 总页数
     */
    @ApiModelProperty(value = "总页数", dataType = "int")
    private Integer totalPage;
    /**
     * 当页记录数量
     */
    @ApiModelProperty(value = "当页记录数量", dataType = "int")
    private Integer pageSize;
    /**
     * 记录总数
     */
    @ApiModelProperty(value = "记录总数", dataType = "int")
    private Long total;
    /**
     * 元素列表
     */
    @ApiModelProperty(value = "当前页元素", dataType = "int")
    private List<T> rows;

    /**
     * 下一页页码
     */
    @ApiModelProperty(value = "下一页页码，没有下一页返回 -1", dataType = "int")
    private Integer nextPageNum;

    /**
     * 从 Spring 的 Page 构造有参构造器
     * 由于 PageFrm 从 1 开始分页，
     * JPA 从数据库查出来是从 0 开始分页，
     * 所以这里手动 + 1
     *
     * @param page 默认的Spring分页对象
     */
    public PageVO(Page<T> page) {
        this.pageNum = page.getNumber() + 1;
        this.pageSize = page.getSize();
        this.totalPage = page.getTotalPages();
        this.rows = page.getContent();
        this.total = page.getTotalElements();
        this.nextPageNum = page.getNumber() + 1 < page.getTotalPages() ? this.pageNum + 1 : -1;
    }

    /**
     * 从 远程请求 中的 PageVO 构造
     */
    public <R> PageVO<R> mapRows(Function<? super T, ? extends R> converter) {
        return PageVO.<R>builder()
                .total(this.total)
                .pageNum(this.pageNum)
                .pageSize(this.pageSize)
                .totalPage(this.totalPage)
                .rows(this.rows.stream().map(converter).collect(Collectors.toList()))
                .nextPageNum(this.nextPageNum)
                .build();
    }

    /**
     * 获取分页对象
     *
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @param total 总数
     * @param list 分页集合数据
     * @param <T> 泛型
     * @return 返回PageVO对象
     */
    public static <T> PageVO<T> of(int pageNum, int pageSize, int total, List<T> list) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
        PageImpl<T> retPage = new PageImpl<>(list, pageable, total);
        return new PageVO<>(retPage);
    }

    /**
     * 获取分页对象
     *
     * @return {@link Pageable}
     */
    public Pageable getPageable() {
        return PageRequest.of(this.pageNum - 1, pageSize);
    }
}
